/**
 *	@file	fld_pmtel.c
 *	@brief	フィールド　電話監視
 *	@author	Miyuki Iwasawa
 *	@date	08.01.28
 */
#include "common.h"

#include "fieldsys.h"
#include "system/pm_str.h"
#include "system/msgdata.h"
#include "system/buflen.h"
#include "system/snd_tool.h"
#include "tel/pmtel_def.h"
#include "tel/pmtel_datman.h"
#include "field/situation_local.h"
#include "field/syswork.h"
#include "field/zonedata.h"
#include "field/script.h"
#include "field/evwkdef.h"
#include "field/sysflag.h"
#include "fielddata/maptable/zone_id.h"
#include "savedata/gametime.h"
#include "savedata/misc.h"
#include "msgdata/msg.naix"

#include "savedata/pgear_sv_util.h"

#define __FLD_PMTEL_H_GLOBAL
#include "fld_pmtel.h"
#include "tel/pmtel_book.h"
#include "fld_pmtel_local.h"

#include "fielddata/script/common_scr_def.h"

#define PMTEL_HEAP		(HEAPID_FIELD)

///プロトタイプ
static void sub_call_se_set(FLD_PMTEL_WORK* wk,BOOL on);
static int sub_reserve_receive(FLD_PMTEL_WORK* wk,PMTEL_BOOK_MAN* book,int zone_id);
static u8 sub_sel_target_normal(FLD_PMTEL_WORK* wk,PMTEL_BOOK_MAN* book,int zone_id);
static u8 sub_sel_target_reserve(FLD_PMTEL_WORK* wk,PMTEL_BOOK_MAN* book,int zone_id);

/**
 *	@brief	フィールド　ポケギア電話　着信者名文字列取得
 *
 *	@param	heapID	利用するヒープ
 *	@return	STRBUF*
 *
 *	着信中の相手の名前文字列をSTRBUFに確保して返します
 *	利用後にSTRBUF_Delete()で解放してください
 */
STRBUF* FldPMTel_CallNameStrAlloc(FLD_PMTEL_WORK* wk,int heapID)
{
	STRBUF* buf;
	MSGDATA_MANAGER* man;

	if(!wk->call_f || wk->number >= PMTEL_NUMBER_MAX){
		//空文字列を返す
		buf = STRBUF_Create(BUFLEN_PERSON_NAME,heapID);
	}else{
		man = MSGMAN_Create(MSGMAN_TYPE_DIRECT,ARC_MSG,PMTelData_GetPersonalMsgArcID(wk->number),heapID);
		buf = MSGMAN_AllocString(man, 0);
		MSGMAN_Delete(man);
	}
	return buf;
}

/**
 *	@brief	フィールド　ポケギア電話　着信パラメータセット
 */
void FldPMTel_CallParamSet(FLD_PMTEL_WORK* wk,const u8 number,const u8 group,u8 group_num,const u8 ev_type,const u8 ev_id)
{
	if(number >= PMTEL_NUMBER_MAX){
		wk->number = PMTEL_NUMBER_NULL;
		wk->ev_group = 0xFF;	//無効グループ設定しておく
		wk->ev_group_num = 0;
		GF_ASSERT_MSG(0,"不正な電話番号 = %d > MAX = %d\n",number,PMTEL_NUMBER_MAX);
	}else{
		wk->number = number;
		wk->ev_group = group;
		wk->ev_group_num = group_num;
	}
	wk->ev_type = ev_type;
	wk->ev_id = ev_id;
}

/**
 *	@brief	ポケギア　着信パラメータ取得
 */
u8 FldPMTel_CallParamGet(FLD_PMTEL_WORK* wk,PMTEL_CALL_PARAM* pc)
{
	MI_CpuClear8(pc,sizeof(PMTEL_CALL_PARAM));
	if(wk->number >= PMTEL_NUMBER_MAX){
		GF_ASSERT_MSG(0,"不正な電話番号 = %d > MAX = %d\n",wk->number,PMTEL_NUMBER_MAX);
		//保険で当たり障りのないデータをいれておく
		pc->group = 0xFF;
		return PMTEL_NUMBER_NULL;
	}else{
		pc->group = wk->ev_group;
		pc->group_num = wk->ev_group_num;
		pc->tel_type = wk->ev_type;
		pc->tel_id = wk->ev_id;
		pc->reserve_id = wk->reserve_id;
		return wk->number;
	}
}

/**
 *	@brief	電話　着信抽選
 */
BOOL FldPMTel_CheckCallup(FLD_PMTEL_WORK* wk)
{
	int ret;
	u8 number;
	u32 rand;
	PMTEL_BOOK_MAN* book;
	LOCATION_WORK * now = Situation_GetNowLocation(SaveData_GetSituation(wk->save));

	//規定ゾーンでは着信しない
	if(!ZoneData_GetEnableTelReceiveFlag(now->zone_id)){
		return FALSE;
	}

	//既に起動しているか、インターバル中
	if(wk->call_f || wk->count < wk->interval){
		return FALSE;
	}
	book = PMTelBookData_AllocAll(PMTEL_HEAP);

	//予約着信抽選
	ret = sub_reserve_receive(wk,book,now->zone_id);

	if(ret){
		PMTelBookData_Free(book);

		if(ret == 2){	//強制受信
			wk->fsys->sublcd_menu_lock_passive = 1;
			EventSet_Script(wk->fsys, SCRID_CALL_PGEAR_TEL_EV_CHECK, NULL);
			return TRUE;
		}else{	//任意受信
			sub_call_se_set(wk,TRUE);
		}
		return FALSE;
	}

	rand = gf_mtRand()%100;
	if(rand > wk->per){
		PMTelBookData_Free(book);
		wk->count = 0;
		return FALSE;
	}
	//ランダム着信抽選
	ret = sub_sel_target_normal(wk,book,now->zone_id);
	PMTelBookData_Free(book);

	if(!ret){
		wk->count = 0;	//カウンタリセット
	}
	return FALSE;
}


///////////////////////////////////////////////////////////////////////////////////
////static

static inline u16 get_rnd(u16 num)
{
	u32 key,rnd;
	key = num*100;
	rnd = gf_mtRand()%key;

	return (rnd/100);
}

/**
 *	@brief	ランダム着信者抽選
 */
static u8 sub_sel_target_normal(FLD_PMTEL_WORK* wk,PMTEL_BOOK_MAN* book,int zone_id)
{
	u8	i,max,num,tnum,group;
	PMTEL_NUMBER *tbl,*target;
	EVENTWORK * ev = SaveData_GetEventWork(wk->save);
	MYSTATUS * my = SaveData_GetMyStatus(wk->save);
	MISC * misc = SaveData_GetMisc(wk->save);

	//登録数取得
	max = PGearSv_GetTelBookEntryNum(wk->pgear_sv);

	//登録データ取得
	target = PGearSv_GetTelBook(wk->pgear_sv,PMTEL_HEAP);

	//抽選テーブルワーク取得
	tbl = sys_AllocMemoryLo(PMTEL_HEAP,sizeof(PMTEL_NUMBER)*max);
	MI_CpuFill8(tbl,PMTEL_NUMBER_NULL,sizeof(PMTEL_NUMBER)*max);

	//抽選ターゲットになるグループを抽選
	{
		u16 rnd = gf_rand()%1000;
		if(rnd < 500){
			group = 0;
		}else if(rnd < 800){
			group = 1;
		}else{
			group = 2;
		}
		IWASAWA_PRINT("PMTel GroupRnd = %d, group = %d\n",rnd,group);
	}
#ifdef PM_DEBUG
	if(wk->deb_group > 0){
		group = wk->deb_group-1;
	}
	wk->deb_group_ct[group]++;
#endif

	//ランダム抽選ターゲットになる番号を列挙
	num = 0;
	for(i = 0;i < max;i++){
		if(book->data[target[i]].group != group){	//抽選されたグループでない
			continue;
		}
		//ランダム抽選ターゲットなら候補に追加
		if(	(book->data[target[i]].play_list == TEL_PLAYL_REVENGE) ||
			(book->data[target[i]].play_list == TEL_PLAYL_LEADER) ||
			(book->data[target[i]].play_list == TEL_PLAYL_SUPPORT) ||
			(book->data[target[i]].play_list == TEL_PLAYL_AOI) ||
			(book->data[target[i]].play_list == TEL_PLAYL_MIC)
			){
			tbl[num++] = target[i];
		}
	}
	if(num == 0){
		//抽選対象がいない
		sys_FreeMemoryEz(target);
		sys_FreeMemoryEz(tbl);
		return FALSE;
	}
	//テーブルの中身はもう要らないのでクリアして使いまわし
	MI_CpuFill8(target,PMTEL_NUMBER_NULL,sizeof(PMTEL_NUMBER)*max);

	//着信フラグ&&同一ゾーンチェック
	{
		u8 entry = 0,no;
		GMTIME* time = SaveData_GetGameTime(wk->save);
		u8 hour = time->sv_time.hour;
		u8 mushitori = SysFlag_MushitoriCheck(ev);
		tnum = 0;
		//現在のストック数取得
		entry = MISC_PMTelNumberStockNumGet(misc,group);

		//候補が既に0ならフラグ全クリア
		if(entry == num){
			MISC_PMTelNumberStockClear(misc,group);
		}
		//着信フラグチェック
		for(i = 0;i < num;i++){
			if(book->data[tbl[i]].map_id == zone_id){
				continue;	//同一マップ内では着信しない
			}
			if(MISC_PMTelNumberStockCheck(misc,group,tbl[i])){
				continue;	//フラグがOnなら着信しない
			}
			if(tbl[i] == PMTEL_NUMBER_AOI){
				//アオイの場合、ラジオの時間帯&ラジオ塔占拠中以外だけ抽選対象に含める
				if(PMTelData_IsAoiWorking(hour) || SysWork_CheckDuaringTheRadioTowerEvent(ev)){
					continue;
				}
			}
			if(book->data[tbl[i]].map_id == ZONE_ID_D22R0101 && mushitori){
				continue;	//自然公園トレーナーは虫取り大会中はhitしない
			}
			target[tnum++] = tbl[i];
		}
		if(tnum != 0){
			//着信セット
			no = get_rnd(tnum);
			FldPMTel_CallParamSet(wk,target[no],group,num,TEL_CALL_NORMAL,0);
			FldPMTel_CallupFlagSet(wk);
			sub_call_se_set(wk,TRUE);
		}
	}
	sys_FreeMemoryEz(target);
	sys_FreeMemoryEz(tbl);

	return tnum;
}


typedef struct _PMTEL_RESREVE_PARAM{
	u8	number;
	u16	data;
	u8	force_f;	//強制受信フラグ
}PMTEL_RESERVE_PARAM;

#include "tel/pmtel_dat_simple.h"
static const PMTEL_RESERVE_PARAM DATA_PMTelReserveParamTbl[PMTEL_RESERVE_ID_MAX] = {
 {PMTEL_NUMBER_UTSUGI,TEL_TK_UTSUGI_EGG_HATCH,FALSE},	//0
 {PMTEL_NUMBER_UTSUGI,TEL_TK_UTSUGI_EV_POKERUS,FALSE},	//1
 {PMTEL_NUMBER_CYCLE,TEL_TK_CYCLE_TRANSFER,TRUE},		//2
 {PMTEL_NUMBER_MASAKI,TEL_TK_MASAKI_BOX_FULL,TRUE},		//3
 {PMTEL_NUMBER_OOKIDO,0,FALSE},							//4
 {PMTEL_NUMBER_GRANDPA,0,FALSE},						//5
 {PMTEL_NUMBER_SAFARI,0,FALSE},							//6
 {PMTEL_NUMBER_SAFARI,TEL_TK_SAFARI_EV_M2_NOTICE,TRUE},	//7
 {PMTEL_NUMBER_SAFARI,TEL_TK_SAFARI_EV_OBJ_ADD_INI,TRUE},	//8
 {PMTEL_NUMBER_SAFARI,TEL_TK_SAFARI_EV_OBJ_ADD,TRUE},		//9
 {PMTEL_NUMBER_SAFARI,TEL_TK_SAFARI_EV_OBJ_ADD_END,TRUE},	//10
 {PMTEL_NUMBER_SAFARI,TEL_TK_SAFARI_EV_OBJ_ADD_ALL,TRUE},	//11
 {PMTEL_NUMBER_MAMA,TEL_TK_MAMA_EMBEZZLEMENT01,FALSE},		//12
};

/**
 *	@brief	予約着信抽選
 */
static int sub_reserve_receive(FLD_PMTEL_WORK* wk,PMTEL_BOOK_MAN* book,int zone_id)
{
	u8 ret = sub_sel_target_reserve(wk,book,zone_id);
	if(ret == 0xFF){
		return FALSE;
	}
	FldPMTel_CallParamSet(wk,
		DATA_PMTelReserveParamTbl[ret].number,0xFF,0,
		TEL_RECEIVE_COUNTER,
		DATA_PMTelReserveParamTbl[ret].data );
	FldPMTel_CallupFlagSet(wk);

	//予約ID保存
	wk->reserve_id = ret;
	OS_Printf("# PMTEL ReserveCallStart %d,%d,%d\n",ret,0,0);
	return 1+DATA_PMTelReserveParamTbl[ret].force_f;
}

/**
 *	@brief	予約着信者抽選
 */
static u8 sub_sel_target_reserve(FLD_PMTEL_WORK* wk,PMTEL_BOOK_MAN* book,int zone_id)
{
	int i,num;
	u8	no;
	u8	*tbl;
	PMTEL_BOOK* pb;

	tbl = sys_AllocMemoryLo(PMTEL_HEAP,sizeof(u8)*PMTEL_RESERVE_ID_MAX);
	MI_CpuClear8(tbl,sizeof(u8)*PMTEL_RESERVE_ID_MAX);

	num = 0;
	for(i =0 ;i < PMTEL_RESERVE_ID_MAX;i++){
		if(	!PMTelSv_CallReserveCheck(wk->tel_sv,i)){
			continue;
		}
		pb = &book->data[DATA_PMTelReserveParamTbl[i].number];
		if(pb->id == PMTEL_NUMBER_GRANDPA){
			if(PGearSv_IsTelNumberEntry(wk->pgear_sv,PMTEL_NUMBER_GRANDPA) == PMTEL_NUMBER_NULL){
				continue;	//じいちゃんは登録していないとかかってこない
			}
		}else if(pb->map_id == zone_id){
			continue;	//同一マップ内では着信しない(じいちゃんは同一マップでも着信する)
		}
		tbl[num++] = i;
	}
	if(num == 0){
		//予約なし
		sys_FreeMemoryEz(tbl);
		return 0xFF;
	}
	no = tbl[gf_rand()%num];
	sys_FreeMemoryEz(tbl);
	return no;
}

/**
 *	@brief	着信音のオン/オフ
 */
static void sub_call_se_set(FLD_PMTEL_WORK* wk,BOOL on)
{
#if 0
	if(on){
		Snd_SePlay(SE_PHONE_LOOP);
	}else{
		Snd_SeStopBySeqNo(SE_PHONE_LOOP,1);
	}
	wk->se_f = on;
#else
	FldPMTel_PhoneSeSet(wk,on);
#endif
}

///////////////////////////////////////////////////////////////////////////////////
////デバッグ用
#ifdef PM_DEBUG
/**
 *	@brief	電話着信抽選の間隔を指定
 */
void DNumInput_TelIntervalSet(FIELDSYS_WORK* fsys,u32 param,u32 value)
{
	FLD_PMTEL_WORK* wk = fsys->pmtel_wk;

	switch(param){
	case 0:
		if(value < 1){
			value = 1;
		}
		if(value > 30){
			value = 30;
		}
		wk->interval = value;
		break;
	case 1:
		if(value < 3){
			value = 3;
		}
		if(value >= 60){
			value = 60;
		}
		wk->timeout =(u16) value;
		break;
	case 2:
		if(value > 100){
			value = 100;
		}
		wk->per = value;
		break;
	case 3:
		wk->deb_per_fix = value;
		break;
	case 4:
		wk->deb_group = value;
		break;
	case 5:
		if(value){	//いきなりちゃくしん
			wk->per = 100;
			wk->count = wk->interval;
		}
		break;
	case 6:	//タケノリカウンター
		PMTelSv_SetTakenoriCounter(SaveData_GetPMTelSave(fsys->savedata),value);
		break;
	case 7:	//タケノリフラグ
		PMTelSv_TakenoriFlagSet(SaveData_GetPMTelSave(fsys->savedata),value);
		break;
	case 8:		//グループカウンター
	case 9:		//グループカウンター
	case 10:	//グループカウンター
		wk->deb_group_ct[param-8] = value;
		break;
	case 11:	//カウンター
		wk->count = value;
		break;
	}
}

/*
 *	@brief	電話着信抽選の間隔を取得
 */
u32 DNumInput_TelIntervalGet(FIELDSYS_WORK* fsys,u32 param)
{
	FLD_PMTEL_WORK* wk = fsys->pmtel_wk;

	switch(param){
	case 0:
		return wk->interval;
	case 1:
		return wk->timeout;
	case 2:
		return wk->per;
	case 3:
		return wk->deb_per_fix;
	case 4:
		return wk->deb_group;
	case 5:	//いきなり着信
		return 0;
	case 6:	//タケノリカウンター
		return PMTelSv_GetTakenoriCounter(SaveData_GetPMTelSave(fsys->savedata));
	case 7:	//タケノリフラグ
		return PMTelSv_TakenoriFlagGet(SaveData_GetPMTelSave(fsys->savedata));
	case 8:		//グループカウンター
	case 9:		//グループカウンター
	case 10:	//グループカウンター
		return wk->deb_group_ct[param-8];
	case 11:	//カウンター
		return wk->count;
	}
	return 0;
}

/**
 *	@brief	電話着信フラグのセット
 */
void DNumInput_TelStockFlagSet(FIELDSYS_WORK* fsys,u32 param,u32 value)
{
	MISC* misc = SaveData_GetMisc(fsys->savedata);

	MISC_PMTelNumberStockSetFromIdx(misc,param,value);
}

u32 DNumInput_TelStockFlagGet(FIELDSYS_WORK* fsys,u32 param)
{
	u8 number;
	MISC* misc = SaveData_GetMisc(fsys->savedata);

	number = MISC_PMTelNumberStockGetFromIdx(misc,param);
	if(number >= PMTEL_NUMBER_MAX){
		return PMTEL_NUMBER_NULL;
	}
	return number;
}

#endif	//PM_DEBUG